/*
 * 
 *	Copyright (C) 2011 -- Alfred Reibenschuh
 *
 * 	This program is free software; you can redistribute it and/or 
 *	modify it under the terms of the GNU General Public License as 
 *	published by the Free Software Foundation; either version 2 of 
 *	the License, or (at your option) any later version.
 *
 *	This program is distributed in the hope that it will be useful, 
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 *	GNU General Public License for more details.
 * 
 */

package redoak.php.snmp;

import java.io.IOException;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;

import com.caucho.quercus.annotation.Optional;
import com.caucho.quercus.env.ArrayValue;
import com.caucho.quercus.env.ArrayValueImpl;
import com.caucho.quercus.env.BooleanValue;
import com.caucho.quercus.env.Env;
import com.caucho.quercus.env.Value;
import com.caucho.quercus.module.AbstractQuercusModule;
import com.caucho.util.L10N;

public abstract class AbstractSnmpModule extends AbstractQuercusModule
{
	private static final Logger log
	= Logger.getLogger(AbstractSnmpModule.class.getName());
	private static final L10N L = new L10N(AbstractSnmpModule.class);

	public String []getLoadedExtensions()
	{
		return new String[] { "snmp" };
	}
	
	public abstract Value snmp_session(Env env, String hostname, String community, @Optional Integer timeout, @Optional Integer retries);
	public abstract Value snmp2c_session(Env env, String hostname, String community, @Optional Integer timeout, @Optional Integer retries);

	public void snmp_close(Env env, Value psession)
	{
		ISnmpModuleSession session = (ISnmpModuleSession)psession.toJavaObject();
		session.close();
	}

	private Object[] snmp_get_impl(Env env, Value psession, String oid)
	{
		ISnmpModuleSession session = (ISnmpModuleSession)psession.toJavaObject();
		Object[] s = null;
		try {
			s = session.snmp_get(oid);
		} catch (TimeoutException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return s;
	}

	public Value snmp_get_asobject(Env env, Value psession, String oid)
	{
		Object[] s = snmp_get_impl(env, psession, oid);

		if(s!=null)
		{
			ArrayValue av = new ArrayValueImpl();
			av.put("oid", s[0].toString());
			av.put("type", (Integer)s[1]);
			av.put("value", s[2].toString());
			return av;
		}
		return BooleanValue.FALSE;
	}

	public Value snmp_get_asvalue(Env env, Value psession, String oid)
	{
		Object[] s = snmp_get_impl(env, psession, oid);

		if(s!=null)
		{
			return env.createString(s[2].toString());
		}
		return BooleanValue.FALSE;
	}

	//string snmpget  ( string $hostname  , string $community  , string $object_id  [, int $timeout  [, int $retries  ]] )
	public Value snmpget(Env env, String hostname, String community, String oid, @Optional Integer timeout, @Optional Integer retries)
	{
		Value psession = snmp_session(env, hostname, community, timeout, retries);
		Value ret = snmp_get_asvalue(env, psession, oid);
		snmp_close(env, psession);
		return ret;
	}

	public Value snmp_get(Env env, Value psession, String oid)
	{
		return snmp_get_asobject(env, psession, oid);
	}


	private Object[] snmp_next_impl(Env env, Value psession, String oid)
	{
		ISnmpModuleSession session = (ISnmpModuleSession)psession.toJavaObject();
		Object s[] = null;
		try {
			s = session.snmp_next(oid);
		} catch (TimeoutException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return s;
	}

	public Value snmp_next_asobject(Env env, Value psession, String oid)
	{
		Object[] s = snmp_next_impl(env, psession, oid);

		if(s!=null)
		{
			ArrayValue av = new ArrayValueImpl();
			av.put("oid", s[0].toString());
			av.put("type", (Integer)s[1]);
			av.put("value", s[2].toString());
			return av;
		}
		return BooleanValue.FALSE;
	}

	public Value snmp_next_asvalue(Env env, Value psession, String oid)
	{
		Object[] s = snmp_next_impl(env, psession, oid);

		if(s!=null)
		{
			return env.createString(s[2].toString());
		}
		return BooleanValue.FALSE;
	}

	//string snmpgetnext  ( string $host  , string $community  , string $object_id  [, int $timeout  [, int $retries  ]] )
	public Value snmpgetnext(Env env, String hostname, String community, String oid, @Optional Integer timeout, @Optional Integer retries)
	{
		Value psession = snmp_session(env, hostname, community, timeout, retries);
		Value ret = snmp_next_asvalue(env, psession, oid);
		snmp_close(env, psession);
		return ret;
	}

	public Value snmp_getnext(Env env, Value psession, String oid)
	{
		return snmp_next_asobject(env, psession, oid);
	}

	public Value snmp_set_impl(Env env, Value psession, String oid, String type, Value value)
	{
		ISnmpModuleSession session = (ISnmpModuleSession)psession.toJavaObject();
		try {
			return env.wrapJava(session.snmp_set(oid, type, value.toJavaObject().toString()), true);
		} catch (TimeoutException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return BooleanValue.FALSE;
	}
	/*
	bool snmpset  ( string $hostname  , string $community  , string $object_id  , string $type  , mixed $value  [, int $timeout  [, int $retries  ]] )
	Returns TRUE on success or FALSE on failure. 

	The "type" parameter must be one of the following, depending on the type of
	variable to set on the SNMP host:

	i    INTEGER
	u    unsigned INTEGER
	t    TIMETICKS
	a    IPADDRESS
	o    OBJID
	s    STRING
	x    HEX STRING
	d    DECIMAL STRING
	*/
	public Value snmpset(Env env, String hostname, String community, String oid, String type, Value value, @Optional Integer timeout, @Optional Integer retries)
	{
		Value psession = snmp_session(env, hostname, community, timeout, retries);
		Value ret = snmp_set(env, psession, oid, type, value);
		snmp_close(env, psession);
		return ret;
	}

	public Value snmp_set(Env env, Value psession, String oid, String type, Value value)
	{
		return snmp_set_impl(env, psession, oid, type, value);
	}

	public Object[][] snmp_walk_impl(Env env, Value psession, String oid)
	{
		ISnmpModuleSession session = (ISnmpModuleSession)psession.toJavaObject();
		try {
			return session.snmp_walk(oid, false);
		} catch (TimeoutException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	public Value snmp_walk_asobject(Env env, Value psession, String oid)
	{
		Object[][] s = snmp_walk_impl(env, psession, oid);

		if(s!=null)
		{
			ArrayValue av = new ArrayValueImpl();
			for(Object[] vb : s)
			{
				ArrayValue avp = new ArrayValueImpl();
				avp.put("index", vb[0].toString().substring(oid.length()));
				avp.put("oid", vb[0].toString());
				avp.put("type", (Integer)vb[1]);
				avp.put("value", vb[2].toString());
				av.put(avp);
			}
			return av;
		}
		return BooleanValue.FALSE;
	}

	public Value snmp_walk_asvalue(Env env, Value psession, String oid)
	{
		Object[][] s = snmp_walk_impl(env, psession, oid);

		if(s!=null)
		{
			ArrayValue av = new ArrayValueImpl();
			for(Object[] vb : s)
			{
				av.put(env.createString(vb[2].toString()));
			}
			return av;
		}
		return BooleanValue.FALSE;
	}

	public Value snmp_walk(Env env, Value psession, String oid)
	{
		return snmp_walk_asobject(env, psession, oid);
	}
	
	//array snmpwalk  ( string $hostname  , string $community  , string $object_id  [, int $timeout  [, int $retries  ]] )
	//Returns an array of SNMP object values starting from the object_id  as root or FALSE on error.
	public Value snmpwalk(Env env, String hostname, String community, String oid, @Optional Integer timeout, @Optional Integer retries)
	{
		Value psession = snmp_session(env, hostname, community, timeout, retries);
		Value ret = snmp_walk_asvalue(env, psession, oid);
		snmp_close(env, psession);
		return ret;
	}
	
	//array snmpwalkoid  ( string $hostname  , string $community  , string $object_id  [, int $timeout  [, int $retries  ]] )
	//Returns an associative array with object ids and their respective object value starting from the object_id  as root or FALSE on error. 
	public Value snmpwalkoid(Env env, String hostname, String community, String oid, @Optional Integer timeout, @Optional Integer retries)
	{
		Value psession = snmp_session(env, hostname, community, timeout, retries);
		Value ret = snmp_walk_asobject(env, psession, oid);
		snmp_close(env, psession);
		return ret;
	}

	//array snmprealwalk  ( string $host  , string $community  , string $object_id  [, int $timeout  [, int $retries  ]] )
	public Value snmprealwalk(Env env, String hostname, String community, String oid, @Optional Integer timeout, @Optional Integer retries)
	{
		Value psession = snmp_session(env, hostname, community, timeout, retries);
		Value ret = snmp_walk_asvalue(env, psession, oid);
		snmp_close(env, psession);
		return ret;
	}

	//string snmp2_get  ( string $hostname  , string $community  , string $object_id  [, int $timeout  [, int $retries  ]] )
	public Value snmp2_get(Env env, String hostname, String community, String oid, @Optional Integer timeout, @Optional Integer retries)
	{
		Value psession = snmp2c_session(env, hostname, community, timeout, retries);
		Value ret = snmp_get_asvalue(env, psession, oid);
		snmp_close(env, psession);
		return ret;
	}

	//string snmp2_getnext  ( string $host  , string $community  , string $object_id  [, int $timeout  [, int $retries  ]] )
	public Value snmp2_getnext(Env env, String hostname, String community, String oid, @Optional Integer timeout, @Optional Integer retries)
	{
		Value psession = snmp2c_session(env, hostname, community, timeout, retries);
		Value ret = snmp_next_asvalue(env, psession, oid);
		snmp_close(env, psession);
		return ret;
	}

	//bool snmp2_set  ( string $hostname  , string $community  , string $object_id  , string $type  , mixed $value  [, int $timeout  [, int $retries  ]] )
	//Returns TRUE on success or FALSE on failure. 
	public Value snmp2_set(Env env, String hostname, String community, String oid, String type, Value value, @Optional Integer timeout, @Optional Integer retries)
	{
		Value psession = snmp2c_session(env, hostname, community, timeout, retries);
		Value ret = snmp_set(env, psession, oid, type, value);
		snmp_close(env, psession);
		return ret;
	}

	//array snmp2_walk  ( string $hostname  , string $community  , string $object_id  [, int $timeout  [, int $retries  ]] )
	//Returns an array of SNMP object values starting from the object_id  as root or FALSE on error.
	public Value snmp2_walk(Env env, String hostname, String community, String oid, @Optional Integer timeout, @Optional Integer retries)
	{
		Value psession = snmp2c_session(env, hostname, community, timeout, retries);
		Value ret = snmp_walk_asvalue(env, psession, oid);
		snmp_close(env, psession);
		return ret;
	}

	//snmp2_real_walk (string host, string community, string object_id [, int timeout [, int retries]])
	public Value snmp2_real_walk(Env env, String hostname, String community, String oid, @Optional Integer timeout, @Optional Integer retries)
	{
		Value psession = snmp2c_session(env, hostname, community, timeout, retries);
		Value ret = snmp_walk_asvalue(env, psession, oid);
		snmp_close(env, psession);
		return ret;
	}

	/*
	snmp v3 functions:
	
	snmp3_get (string host, string sec_name, string sec_level, string auth_protocol, string auth_passphrase, string priv_pr)
	snmp3_getnext (string host, string sec_name, string sec_level, string auth_protocol, string auth_passphrase, string pri)
	snmp3_walk (string host, string sec_name, string sec_level, string auth_protocol, string auth_passphrase, string priv_p)
	snmp3_real_walk (string host, string sec_name, string sec_level, string auth_protocol, string auth_passphrase, string p)
	snmp3_set (string host, string sec_name, string sec_level, string auth_protocol, string auth_passphrase, string priv_pr)
	  
	  SNMP_OID_OUTPUT_FULL  (integer)
	    As of 5.2.0 
	SNMP_OID_OUTPUT_NUMERIC (integer)
	    As of 5.2.0 
	
		//void snmp_set_valueretrieval  ( int $method  )
		//int snmp_get_valueretrieval  ( void  )
		//
		//A mild description of these is:
		//	SNMP_VALUE_LIBRARY: This is a string similar to:
		//	"INTEGER: 42"
		//
		//	SNMP_VALUE_PLAIN: This is a string similar to:
		//	"42"
		//
		//	SNMP_VALUE_OBJECT: This is a PHP object like:
		//	object(
		//	"type" => SNMP_INTEGER,
		//	"value" => 42,
		//	)
		//
		//bool snmp_get_quick_print  ( void  ) 
		//void snmp_set_quick_print  ( bool $quick_print  )
		// Sets the value of quick_print within the UCD SNMP library. 
		// When this is set (1), the SNMP library will return 'quick printed' 
		// values. This means that just the value will be printed. When 
		// quick_print is not enabled (default) the UCD SNMP library prints 
		// extra information including the type of the value (i.e. IpAddress or OID). 
		// Additionally, if quick_print is not enabled, the library prints 
		// additional hex values for all strings of three characters or less.
		// By default the UCD SNMP library returns verbose values, quick_print 
		// is used to return only the value.
		//
		//void snmp_set_oid_output_format  ( int $oid_format  )
		//void snmp_set_oid_numeric_print  ( int $oid_numeric_print  )
		//void snmp_set_enum_print  ( int $enum_print  )
		//bool snmp_read_mib  ( string $filename  )
	*/
}
